home *** CD-ROM | disk | FTP | other *** search
- /*
- * This memory allocation code is derived from the GNU memory allocator.
- * Please read the FSF copyright notice at the end of this file.
- */
-
- /*
- * @(#)nmalloc.c 1 (Caltech) 2/21/82
- *
- * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs
- *
- * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD.
- *
- * This is a very fast storage allocator. It allocates blocks of a small
- * number of different sizes, and keeps free lists of each size. Blocks
- * that don't exactly fit are passed up to the next larger size. In this
- * implementation, the available sizes are (2^n)-4 (or -16) bytes long.
- * This is designed for use in a program that uses vast quantities of
- * memory, but bombs when it runs out. To make it a little better, it
- * warns the user when he starts to get near the end.
- *
- * June 84, ACT: modified rcheck code to check the range given to malloc,
- * rather than the range determined by the 2-power used.
- *
- * Jan 85, RMS: calls malloc_warning to issue warning on nearly full.
- * No longer Emacs-specific; can serve as all-purpose malloc for GNU.
- * You should call malloc_init to reinitialize after loading dumped Emacs.
- * Call malloc_stats to get info on memory stats if MSTATS turned on.
- * realloc knows how to return same block given, just changing its size,
- * if the power of 2 is correct.
- *
- * May 88, Univ. of Washington: Significant (but relatively simple)
- * changes to make this code work in a Sequent shared-memory/PRESTO
- * environment.
- *
- * Perhaps the biggest difference is that whenever we have to ask for
- * more space, we get a BIG chunk rather than a relatively small one.
- * Another change is that requests for memory >= the system page size
- * will return memory that is aligned to a page boundary, due to the
- * prevalent use of mmap(2).
- *
- * June 89, Univ. of Washington: Worked on memory alignment bug in malloc().
- *
- * Most of the changes are bracketed by the SHARED and PRESTO $ifdef's.
- *
- */
-
-
- #define SHARED
- #define PRESTO
-
- #include <sys/types.h>
-
- #ifdef SHARED
-
- #ifdef sequent
- #include <parallel/parallel.h>
- #define sbrk shsbrk
- #endif sequent
-
- #ifdef sun
- # define shared /**/
- # define private /**/
- typedef int slock_t;
- # define L_UNLOCKED 0
- # ifdef PRESTO
- # define S_LOCK s_lock
- # define S_UNLOCK s_unlock
- # endif PRESTO
- #endif sun
-
- #ifdef vax
- #define shared /**/
- #define private /**/
- typedef int slock_t;
- #define L_UNLOCKED 0
-
- #ifdef PRESTO
- /*
- * Redefine S_LOCK and S_UNLOCK to be s_lock() and s_unlock(),
- * included in vax_lock.s in Presto source. Should probably be
- * asm macros. On the vax, the shared allocation code won't ld
- * outside of a presto environment.
- */
- #define S_LOCK s_lock
- #define S_UNLOCK s_unlock
- #else
- XXX
- #endif PRESTO
- #endif vax
-
- #ifdef PRESTO
- /*
- * See comment on naming of the memory allocator in misc.c.
- *
- * #define malloc shmalloc
- * #define free shfree
- */
-
- #endif PRESTO
-
- #define mstats shmstats
- #define realloc shrealloc
-
- #endif SHARED
-
- #ifdef PRESTO
- /*
- * These external routines are needed to avoid a deadlock situation where
- * we preempt a thread controlling access to the memory management
- * stuff. Preempting while holding onto this stuff could make things
- * go very very slowly.
- */
-
- extern void enable_interrupts();
- extern int disable_interrupts();
- #endif PRESTO
-
-
- /*
- * Determine which kind of system this is.
- */
- #define BSD42
- #define BSD
- #include <sys/time.h>
- #include <sys/resource.h>
-
- #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
- #define ISFREE ((char) 0x54) /* magic byte that implies free block */
- /* this is for error checking only */
- #define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by
- memalign, with the rest of the word
- being the distance to the true
- beginning of the block. */
-
- /*
- * NBINS == number of "headers" pointing to blocks of size 2**(n+3).
- */
- #define NBINS 30
-
- /*
- * If MSTATS is defined then
- * nmalloc[i] is the difference between the number of mallocs and frees
- * for a given block size.
- */
-
- #ifdef MSTATS
- #ifdef SHARED
- shared static int nmalloc[NBINS];
- shared static int nmal, nfre;
- #else
- static int nmalloc[NBINS];
- static int nmal, nfre;
- #endif
- #endif /* MSTATS */
-
- /*
- * If range checking is not turned on, all we have is a flag indicating
- * whether memory is allocated, an index in nextf[], and a size field; to
- * realloc() memory we copy either size bytes or 1<<(index+3) bytes depending
- * on whether the former can hold the exact size (given the value of
- * 'index'). If range checking is on, we always need to know how much space
- * is allocated, so the 'size' field is only used to remember memory alignment
- */
-
- struct mhead {
- char mh_alloc; /* ISALLOC or ISFREE */
- char mh_index; /* index in nextf[] */
- /* Remainder are valid only when block is allocated */
- unsigned short mh_size; /* size, if < 0x10000 */
- #ifdef rcheck
- unsigned mh_nbytes; /* number of bytes allocated */
- int mh_magic4; /* should be == MAGIC4 */
- #endif /* rcheck */
- };
-
- /*
- * Access free-list pointer of a block.
- * It is stored at block + 4.
- * This is not a field in the mhead structure
- * because we want sizeof (struct mhead)
- * to describe the overhead for when the block is in use,
- * and we do not want the free-list pointer to count in that.
- */
-
- #define CHAIN(a) \
- (*(struct mhead **) (sizeof (char *) + (char *) (a)))
-
- #ifdef rcheck
-
- /*
- * To implement range checking, we write magic values in at the beginning and
- * end of each allocated block, and make sure they are undisturbed whenever a
- * free or a realloc occurs.
- */
-
- /* Written in each of the 4 bytes following the block's real space */
- #define MAGIC1 0x55
-
- /* Written in the 4 bytes before the block's real space */
- #define MAGIC4 0x55555555
-
- #define ASSERT(p) if (!(p)) botch("p"); else
- #define EXTRA 4 /* 4 bytes extra for MAGIC1s */
-
- #else
-
- #define ASSERT(p)
- #define EXTRA 0
-
- #endif /* rcheck */
-
- /*
- * nextf[i] is the pointer to the next free block of size 2^(i+3). The
- * smallest allocatable block is 8 bytes. The overhead information will
- * go in the first int of the block, and the returned pointer will point
- * to the second.
- *
- * busy[i] is meant to indicate that a recursive call to malloc
- * has been made (e.g., via a signal handler). Not used in this
- * (May 88) version.
- */
-
- #ifdef SHARED
- /* nextf[i] is free list of blocks of size 2**(i + 3) */
- shared static struct mhead *nextf[NBINS];
-
- /* busy[i] is nonzero while allocation of block size i is in progress. */
- shared static char busy[NBINS];
-
- /* Number of bytes of writable memory we can expect to be able to get */
- shared static unsigned int lim_data;
-
- /* nonzero once initial bunch of free blocks made */
- shared static int gotpool;
-
- /* Mutex for structure access */
- shared static slock_t lock;
-
- /* System page size in bytes */
- shared static int syspgsize;
-
- #ifdef PRESTO
-
- #define BEGIN_CRITICAL { \
- disable_interrupts(); \
- S_LOCK(&lock); \
- }
-
- #define END_CRITICAL { \
- S_UNLOCK(&lock); \
- enable_interrupts(); \
- }
-
- #else
-
- #define BEGIN_CRITICAL { \
- S_LOCK(&lock); \
- }
-
- #define END_CRITICAL { \
- S_UNLOCK(&lock); \
- }
-
- #endif PRESTO
-
- #else /* not shared */
-
- #ifdef PRESTO
-
- #define BEGIN_CRITICAL disable_interrupts();
- #define END_CRITICAL enable_interrupts();
-
- #else
-
- #define BEGIN_CRITICAL ;
- #define END_CRITICAL ;
-
- #endif PRESTO
-
- /* nextf[i] is free list of blocks of size 2**(i + 3) */
- static struct mhead *nextf[NBINS];
-
- /* busy[i] is nonzero while allocation of block size i is in progress. */
- static char busy[NBINS];
-
- /* Number of bytes of writable memory we can expect to be able to get */
- static unsigned int lim_data;
-
- /* nonzero once initial bunch of free blocks made */
- static int gotpool;
-
- /* System page size in bytes */
- static int syspgsize;
-
- #endif SHARED
-
- char *grab_hunk();
-
- /*
- * BRKSIZELOG2 is log2-3 of the minimum chunk of memory we will ask for
- * if we have to request more memory (ie, via sbrk). In our case we ask for
- * the maximum that will fit in the mh_size field, 65K.
- */
- #define BRKSIZELOG2 13
-
- static morecore (nu) /* ask system for more memory */
- register int nu; /* size index to get more of */
- {
- register char *cp;
- register int nblks;
- register unsigned int siz;
-
- /*
- * On initial startup, get one block of each size up to some reasonable
- * size.
- */
- if (!gotpool) {
- getpool ();
- gotpool = 1;
- if ( nextf[nu] ) return; /* Getpool got it for us */
- }
-
- /*
- * Must be either a big block or we are really out of memory.
- */
- nblks = 1;
- if ((siz = nu) < BRKSIZELOG2)
- nblks = 1 << ((siz = BRKSIZELOG2) - nu);
-
- if ((cp = grab_hunk(1 << (siz + 3))) == (char *) -1)
- return; /* no more room! */
-
- if ((int) cp & 7) {
- /*
- * shouldn't happen, but just in case
- */
- cp = (char *) (((int) cp + 8) & ~7);
- nblks--;
- }
-
- /*
- * save new header and link the nblks blocks together
- */
- nextf[nu] = (struct mhead *) cp;
- siz = 1 << (nu + 3);
- while (1) {
- ((struct mhead *) cp) -> mh_alloc = ISFREE;
- ((struct mhead *) cp) -> mh_index = nu;
- if (--nblks <= 0)
- break;
- CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
- cp += siz;
- }
- CHAIN ((struct mhead *) cp) = 0;
- }
-
- /*
- * Get a chunk of memory from the system. Make sure the pointer that
- * we return is just sizeof(struct mhead) bytes shy of a page boundary.
- * Calls to this function must be serialized.
- */
-
- char *
- grab_hunk(nbytes)
- int nbytes;
- {
- char *cp;
- char *sbrk ();
-
- cp = sbrk(0);
- /*
- * land on pagesize boundaries
- */
- if (((int) cp + sizeof(struct mhead)) & (syspgsize-1)) {
- sbrk (syspgsize - (((int) cp + sizeof( struct mhead)) & (syspgsize-1)));
- }
-
- return(sbrk(nbytes));
- }
-
- /*
- * Get a chunk of memory from the system. Make sure the pointer that
- * we return is just on a page boundary. This memory should **not**
- * be used by the memory allocator.
- */
-
- char *
- grab_nonmalloc_hunk(nbytes)
- int nbytes;
- {
- char *cp;
- char *sbrk ();
-
- BEGIN_CRITICAL;
- cp = sbrk(0);
- /*
- * land on pagesize boundaries
- */
- if (((int) cp) & (syspgsize-1)) {
- sbrk (syspgsize - (((int) cp) & (syspgsize-1)));
- }
-
- cp = sbrk(nbytes);
- END_CRITICAL;
- return cp;
- }
-
- static getpool ()
- {
- register int nu;
- register char *cp;
- int logpgsz;
-
- /* Get 16*pagesize of storage */
- cp = grab_hunk(16*syspgsize);
- if (cp == (char *) -1)
- return;
-
- /*
- /* Divide it into an initial 8-word block
- * plus one block of size 2**nu for nu = 3 ... log2(chunksize*pgsize)-1.
- */
- logpgsz = 8*syspgsize;
- nu = 0;
- while ( ! (logpgsz & 1) ) {
- logpgsz >>= 1;
- nu++;
- }
- logpgsz = nu - 3;
-
- CHAIN (cp) = nextf[0];
- nextf[0] = (struct mhead *) cp;
- ((struct mhead *) cp) -> mh_alloc = ISFREE;
- ((struct mhead *) cp) -> mh_index = 0;
- cp += 8;
-
- for (nu = 0; nu < logpgsz; nu++)
- {
- CHAIN (cp) = nextf[nu];
- nextf[nu] = (struct mhead *) cp;
- ((struct mhead *) cp) -> mh_alloc = ISFREE;
- ((struct mhead *) cp) -> mh_index = nu;
- cp += 8 << nu;
- }
- }
-
- char *malloc (n) /* get a block */
- unsigned n;
- {
- register struct mhead *p;
- register unsigned int nbytes;
- register int nunits = 0;
- int mustalign;
- char *aligned;
- struct mhead *p2;
-
- /*
- * Figure out how many bytes are required, rounding up to the nearest
- * multiple of 4, then figure out which nextf[] area to use.
- */
- if ( !syspgsize ) {
- syspgsize = getpagesize();
- }
-
- /*
- * If asking for >= syspgsize bytes, make sure
- * the return value is page aligned in case of mmap(2).
- */
- if ( n >= syspgsize ) {
- mustalign = 1;
- n += syspgsize;
- }
- else {
- mustalign = 0;
- }
-
- nbytes = (n + sizeof *p + EXTRA + 3) & ~3;
- {
- register unsigned int shiftr = (nbytes - 1) >> 2;
-
- while (shiftr >>= 1)
- nunits++;
- }
-
- BEGIN_CRITICAL;
-
- /* If there are no blocks of the appropriate size, go get some */
- /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
- if (nextf[nunits] == 0)
- morecore (nunits);
-
- /* Get one block off the list, and set the new list head */
- if ((p = nextf[nunits]) == 0) {
- END_CRITICAL;
- return 0;
- }
-
- nextf[nunits] = CHAIN (p);
-
- END_CRITICAL;
-
- /*
- * Check for free block clobbered
- * If not for this check, we would gobble a clobbered free chain ptr
- * and bomb out on the NEXT allocate of this size block
- */
- if (p -> mh_alloc != ISFREE || p -> mh_index != nunits)
- #ifdef rcheck
- botch ("block on free list clobbered");
- #else /* not rcheck */
- abort ();
- #endif /* not rcheck */
-
- /* Fill in the info, and if range checking, set up the magic numbers */
- p -> mh_alloc = ISALLOC;
-
- #ifdef rcheck
- p -> mh_nbytes = n;
- p -> mh_magic4 = MAGIC4;
- {
- register char *m = (char *) (p + 1) + n;
-
- *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
- }
- #else /* not rcheck */
- p -> mh_size = n;
- #endif /* not rcheck */
-
- #ifdef MSTATS
- nmalloc[nunits]++;
- nmal++;
- #endif /* MSTATS */
-
- if ( mustalign ) {
- if ( ((int)(p+1) & (syspgsize-1)) != 0 ) {
- aligned = (char *) (p+1);
- aligned = (char *) (((int)aligned + syspgsize - 1) & -syspgsize);
- p2 = (struct mhead *) aligned - 1;
- p2->mh_size = aligned - (char *)( p + 1 );
- p2->mh_alloc = ISMEMALIGN;
- return aligned;
- }
- }
-
- return (char *) (p + 1);
- }
-
- free (mem)
- char *mem;
- {
- register struct mhead *p;
-
- {
- register char *ap = mem;
-
- if (ap == 0)
- return;
-
- p = (struct mhead *) ap - 1;
- if (p -> mh_alloc == ISMEMALIGN)
- {
- ap -= p->mh_size;
- p = (struct mhead *) ap - 1;
- }
-
- if (p -> mh_alloc != ISALLOC)
- #ifdef rcheck
- abort ();
- #else
- return;
- #endif
- #ifdef rcheck
- ASSERT (p -> mh_magic4 == MAGIC4);
- ap += p -> mh_nbytes;
- ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
- ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1);
- #endif /* rcheck */
-
- }
-
- {
- register int nunits = p -> mh_index;
-
- ASSERT (nunits <= (NBINS-1));
- p -> mh_alloc = ISFREE;
-
- BEGIN_CRITICAL;
-
- /* Put this block on the free list. */
- CHAIN (p) = nextf[nunits];
- nextf[nunits] = p;
-
- #ifdef MSTATS
- nmalloc[nunits]--;
- nfre++;
- #endif /* MSTATS */
-
- END_CRITICAL;
- }
- }
-
-
- #ifdef MSTATS
- /*
- * Return statistics describing allocation of blocks of size 2**n.
- *
- * This seems like a foolish way to do things, but who am I to argue
- * with Stallman, et al.
- */
-
- struct mstats_value {
- int blocksize;
- int nfree;
- int nused;
- };
-
- struct mstats_value malloc_stats (size)
- int size;
- {
- struct mstats_value v;
- register int i;
- register struct mhead *p;
-
- v.nfree = 0;
-
- if (size < 0 || size >= NBINS)
- {
- v.blocksize = 0;
- v.nused = 0;
- return v;
- }
-
- BEGIN_CRITICAL;
- v.blocksize = 1 << (size + 3);
- v.nused = nmalloc[size];
- for (p = nextf[size]; p; p = CHAIN (p))
- v.nfree++;
- END_CRITICAL;
-
- return v;
- }
- #endif /* MSTATS */
-
- char *realloc (mem, n)
- char *mem;
- register unsigned n;
- {
- register struct mhead *p;
- register unsigned int tocopy;
- register unsigned int nbytes;
- register int nunits;
-
- if ((p = (struct mhead *) mem) == 0)
- return malloc (n);
- p--;
- nunits = p -> mh_index;
- ASSERT (p -> mh_alloc == ISALLOC);
-
- #ifdef rcheck
- ASSERT (p -> mh_magic4 == MAGIC4);
- {
- register char *m = mem + (tocopy = p -> mh_nbytes);
- ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
- ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1);
- }
- #else /* not rcheck */
- if (p -> mh_index >= 13)
- tocopy = (1 << (p -> mh_index + 3)) - sizeof *p;
- else
- tocopy = p -> mh_size;
- #endif /* not rcheck */
-
- /* See if desired size rounds to same power of 2 as actual size. */
- nbytes = (n + sizeof *p + EXTRA + 7) & ~7;
-
- /* If ok, use the same block, just marking its size as changed. */
- if (nbytes > (4 << nunits) && nbytes <= (8 << nunits))
- {
- #ifdef rcheck
- register char *m = mem + tocopy;
- *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
- p-> mh_nbytes = n;
- m = mem + n;
- *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1;
- #else /* not rcheck */
- p -> mh_size = n;
- #endif /* not rcheck */
- return mem;
- }
-
- if (n < tocopy)
- tocopy = n;
- {
- register char *new;
-
- if ((new = malloc (n)) == 0)
- return 0;
- bcopy (mem, new, tocopy);
- free (mem);
- return new;
- }
- }
-
- /*
- * The following routines are not used and are left for documentation
- * purposes only.
- */
-
- #ifdef NOTDEF
- char *memalign ( alignment, size)
- unsigned alignment, size;
- {
- register char *ptr = malloc (size + alignment);
- register char *aligned;
- register struct mhead *p;
-
- if (ptr == 0)
- return 0;
- /*
- * If entire block has the desired alignment, just accept it.
- */
- if (((int) ptr & (alignment - 1)) == 0)
- return ptr;
- /* Otherwise, get address of byte in the block that has that alignment. */
- aligned = (char *) (((int) ptr + alignment - 1) & -alignment);
- /* Store a suitable indication of how to free the block,
- so that free can find the true beginning of it. */
- p = (struct mhead *) aligned - 1;
- p -> mh_size = aligned - ptr;
- p -> mh_alloc = ISMEMALIGN;
- return aligned;
- }
-
- /* This runs into trouble with getpagesize on HPUX.
- Patching out seems cleaner than the ugly fix needed.
- char *
- valloc (size)
- {
- return memalign (getpagesize (), size);
- }
- */
-
- get_lim_data ()
- {
- struct rlimit XXrlimit;
-
- getrlimit (RLIMIT_DATA, &XXrlimit);
- #ifdef RLIM_INFINITY
- lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */
- #else
- lim_data = XXrlimit.rlim_cur; /* soft limit */
- #endif
- }
-
- #endif NOTDEF
-
-
-
- /* dynamic memory allocation for GNU.
- Copyright (C) 1985, 1987 Free Software Foundation, Inc.
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
- as you receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1985 Free Software Foundation, Inc."; and include following the
- copyright notice a verbatim copy of the above disclaimer of warranty
- and of this License. You may charge a distribution fee for the
- physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- Mere aggregation of another unrelated program with this program (or its
- derivative) on a volume of a storage or distribution medium does not bring
- the other program under the scope of these terms.
-
- 3. You may copy and distribute this program (or a portion or derivative
- of it, under Paragraph 2) in object code or executable form under the terms
- of Paragraphs 1 and 2 above provided that you also do one of the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
- For an executable file, complete source code means all the source code for
- all modules it contains; but, as a special exception, it need not include
- source code for modules which are standard libraries that accompany the
- operating system on which the executable file runs.
-
- 4. You may not copy, sublicense, distribute or transfer this program
- except as expressly provided under this License Agreement. Any attempt
- otherwise to copy, sublicense, distribute or transfer this program is void and
- your rights to use the program under this License agreement shall be
- automatically terminated. However, parties who have received computer
- software programs from you with this License Agreement will not have
- their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
- programs whose distribution conditions are different, write to the Free
- Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
- worked out a simple rule that can be stated here, but we will often permit
- this. We will be guided by the two goals of preserving the free status of
- all derivatives of our free software and of promoting the sharing and reuse of
- software.
-
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-